#include "abs_device.h"

// 自动初始化注册相关变量
// 设备自动注册初始化函数回调相关变量
struct cc_device_init_node init_device_node[CC_CONFIG_DEVICE_MAX_TYPE] = { 0 };
struct cc_device_init_node* __cc_device_init_node_start = init_device_node;
struct cc_device_init_node* __cc_device_init_node_end = init_device_node;

enum
{
  CC_DEVICE_INIT_OK = 0,
  CC_DEVICE_INIT_REPEAT,
  CC_DEVICE_INIT_TYPE_EXCESS,
};
#define foreach_device_mount(pos) \
  for (pos = __cc_device_init_node_start; pos < __cc_device_init_node_end; pos++)

static int error_flag = CC_DEVICE_INIT_OK;
e_device_err cc_devices_default_exit_cb(void* data)
{

  cc_log("cc_devices_default_exit_cb \r\n");
#if defined(debug_cc_device)
  cc_mqtt_msg_t msg = (cc_mqtt_msg_t)data;
  cc_log(rx_data, "DID:%2d | DTYPE:%2d | CMD:%2d\nCTR_TYPE:%2d | DATA:%s\n", msg->device_id, msg->device_type, msg->cmd, msg->ctrl_type, msg->data);
  cc_log("%s", rx_data);
#endif    // debug_msg
  return DEVICE_EOK;
}

// 设备初始化函数挂载的自动加载
void cc_device_init_mount(device_init_cb func, int device_type)
{
  if (device_type >= CC_DEVICE_TYPE_MAX)
  {
    error_flag = CC_DEVICE_INIT_TYPE_EXCESS;
    return;
  }
  struct cc_device_init_node* ptr = __cc_device_init_node_start;
  if (ptr != __cc_device_init_node_end)
  {
    foreach_device_mount(ptr)
    {
      if (ptr->afunc != 0 && ptr->device_type == device_type)
      {
        error_flag = CC_DEVICE_INIT_REPEAT;
        ptr->device_type = 0xff;
      }
    }
  }
  struct cc_device_init_node* entry = __cc_device_init_node_end;
  entry->afunc = func;
  entry->device_type = device_type;
  __cc_device_init_node_end += 1;
  return;
}

user_device_t cc_device_get(user_device_t devices, uint8_t device_type, uint8_t device_id)
{
  if (devices == CC_NULL)
  {
    cc_log_e("device list is null\r\n");
    return CC_NULL;
  }
  if (device_type == 0xff)
  {
    cc_log_e("the device is a repeat init device can't work,please check code\r\n");
  }
  if (device_type >= CC_CONFIG_DEVICE_MAX_TYPE || device_type < 0)
  {
    cc_log_e("do not have the type:%d please check param or register\r\n", device_type);
    return CC_NULL;
  }
  int i = 0;
  for (i = 0; i < CC_CONFIG_DEVICE_MAX_NUM; i++)
  {
    if (devices[i].device_id == device_id && devices[i].device_type == device_type)
    {
      return &devices[i];
    }
  }
  return CC_NULL;
}

static void cc_devices_set_init_cb(user_device_t devices)
{
  if (devices == CC_NULL)
  {
    cc_log_e("device list is null\r\n");
    return;
  }
  struct cc_device_init_node* fn_ptr = __cc_device_init_node_start;
  int i = 0;
  for (i = 0; i < CC_CONFIG_DEVICE_MAX_NUM; i++)
  {
    // 遍历挂载了初始化回调的节点
    foreach_device_mount(fn_ptr)
    {
      // 如果匹配到就退出 开始下一个设备的遍历
      if (fn_ptr->device_type == devices[i].device_type)
      {
        devices[i].control_exit_cb = cc_devices_default_exit_cb;
        devices[i].read_exit_cb = cc_devices_default_exit_cb;
        devices[i].write_exit_cb = cc_devices_default_exit_cb;
        // 挂载设备自定义的初始化函数
        devices[i].init_cb = fn_ptr->afunc;
        break;
      }
      else
      {
        devices[i].init_cb = CC_NULL;
      }
    }
    // 指针回到表头
    fn_ptr = init_device_node;
  }
}

void cc_devices_exe_init_cb(user_device_t devices)
{

  int i = 0;
  if (devices == CC_NULL)
  {
    cc_log_e("device list is null\r\n");
    return;
  }
  cc_devices_set_init_cb(devices);
  for (i = 0; i < CC_CONFIG_DEVICE_MAX_NUM; i++)
  {
    if (devices[i].device_type != CC_DEVICE_TYPE_UNKNOW)
    {
      if (devices[i].init_cb != CC_NULL)
      {
        cc_log("type:%d id:%d init\r\n", devices[i].device_type, devices[i].device_id);
        devices[i].init_cb(&devices[i]);
        cc_mutex_init(&devices[i].mutex);
        cc_queue_init(&devices[i].mqtt_queue, devices[i].mqtt_queue_storage_arr, CC_CONFIG_DEVICE_QUEUE_LENGTH, CC_CONFIG_DEVICE_QUEUE_SIZE);
      }
      else
      {
        cc_log_e("device_type:%d no register init cb,please register\r\n", devices[i].device_type);
      }
    }
  }
}

extern user_device devices[CC_CONFIG_DEVICE_MAX_NUM];
int user_device_init()
{
  // 执行所有设备的初始化回调
  if (error_flag)
  {
    cc_log_e("device init error(%d) please check\r\n", error_flag);
    cc_log_e("the app will easy dump\r\n");
    return 0;
  }
  cc_devices_exe_init_cb(devices);
  return 1;
}
CC_INIT_COMPONENT_REGISTER(user_device_init);